//	---------------------------------------------------------------------------
//
//	@file		TwEventSFML.cpp
//	@brief		Helper:
//				translate and re-send mouse and keyboard events
//				from SFML 1.6 event loop to AntTweakBar
//
//	@author		Philippe Decaudin
//	@license	This file is part of the AntTweakBar library.
//				For conditions of distribution and use, see License.txt
//
//	---------------------------------------------------------------------------

#if !defined TW_NO_SFML_EVENTS

#include "MiniSFML16.h" // a subset of SFML 1.6 headers needed to compile TwEventSFML.cpp
// note: AntTweakBar.dll does not need to link with SFML,
// it just needs some definitions for its helper functions.

#include <AntTweakBar.h>


//	TwEventSFML returns zero if msg has not been handled,
//	and a non-zero value if it has been handled by the AntTweakBar library.
int TW_CALL TwEventSFML(const void *sfmlEvent, unsigned char majorVersion, unsigned char minorVersion)
{
	// Assume version 1.6 (will possibly not work for version != 1.6, but give it a chance)
	/*
	if (majorVersion > 1 || (majorVersion == 1 && minorVersion > 6)
	{
		static const char *g_ErrBadSFMLVersion = "Unsupported SFML version";
		TwSetLastError(g_ErrBadSFMLVersion);
		return 0;
	}
	*/
	(void)majorVersion, (void)minorVersion;

	int handled = 0;
	const sf::Event *event = (const sf::Event *)sfmlEvent;
	TwMouseAction mouseAction;
	int key = 0;
	static int s_KMod = 0;
	static bool s_PreventTextHandling = false;
	static int s_WheelPos = 0;

	if (event == NULL)
		return 0;

	switch (event->Type)
	{
	case sf::Event::KeyPressed:
		s_PreventTextHandling = false;
		s_KMod = 0;
		if (event->Key.Shift)	s_KMod |= TW_KMOD_SHIFT;
		if (event->Key.Alt)		s_KMod |= TW_KMOD_ALT;
		if (event->Key.Control) s_KMod |= TW_KMOD_CTRL;
		key = 0;
		switch (event->Key.Code)
		{
		case sf::Key::Escape:
			key = TW_KEY_ESCAPE;
			break;
		case sf::Key::Return:
			key = TW_KEY_RETURN;
			break;
		case sf::Key::Tab:
			key = TW_KEY_TAB;
			break;
		case sf::Key::Back:
			key = TW_KEY_BACKSPACE;
			break;
		case sf::Key::PageUp:
			key = TW_KEY_PAGE_UP;
			break;
		case sf::Key::PageDown:
			key = TW_KEY_PAGE_DOWN;
			break;
		case sf::Key::Up:
			key = TW_KEY_UP;
			break;
		case sf::Key::Down:
			key = TW_KEY_DOWN;
			break;
		case sf::Key::Left:
			key = TW_KEY_LEFT;
			break;
		case sf::Key::Right:
			key = TW_KEY_RIGHT;
			break;
		case sf::Key::End:
			key = TW_KEY_END;
			break;
		case sf::Key::Home:
			key = TW_KEY_HOME;
			break;
		case sf::Key::Insert:
			key = TW_KEY_INSERT;
			break;
		case sf::Key::Delete:
			key = TW_KEY_DELETE;
			break;
		case sf::Key::Space:
			key = TW_KEY_SPACE;
			break;
		default:
			if (event->Key.Code >= sf::Key::F1 && event->Key.Code <= sf::Key::F15)
				key = TW_KEY_F1 + event->Key.Code - sf::Key::F1;
			else if (s_KMod & TW_KMOD_ALT)
			{
				if (event->Key.Code >= sf::Key::A && event->Key.Code <= sf::Key::Z)
				{
					if (s_KMod & TW_KMOD_SHIFT)
						key = 'A' + event->Key.Code - sf::Key::A;
					else
						key = 'a' + event->Key.Code - sf::Key::A;
				}
			}
		}
		if (key != 0)
		{
			handled = TwKeyPressed(key, s_KMod);
			s_PreventTextHandling = true;
		}
		break;
	case sf::Event::KeyReleased:
		s_PreventTextHandling = false;
		s_KMod = 0;
		break;
	case sf::Event::TextEntered:
		if (!s_PreventTextHandling && event->Text.Unicode != 0 && (event->Text.Unicode & 0xFF00) == 0)
		{
			if ((event->Text.Unicode & 0xFF) < 32) // CTRL+letter
				handled = TwKeyPressed((event->Text.Unicode & 0xFF)+'a'-1, TW_KMOD_CTRL|s_KMod);
			else
				handled = TwKeyPressed(event->Text.Unicode & 0xFF, 0);
		}
		s_PreventTextHandling = false;
		break;
	case sf::Event::MouseMoved:
		handled = TwMouseMotion(event->MouseMove.X, event->MouseMove.Y);
		break;
	case sf::Event::MouseButtonPressed:
	case sf::Event::MouseButtonReleased:
		mouseAction = (event->Type==sf::Event::MouseButtonPressed) ? TW_MOUSE_PRESSED : TW_MOUSE_RELEASED;
		switch (event->MouseButton.Button)
		{
		case sf::Mouse::Left:
			handled = TwMouseButton(mouseAction, TW_MOUSE_LEFT);
			break;
		case sf::Mouse::Middle:
			handled = TwMouseButton(mouseAction, TW_MOUSE_MIDDLE);
			break;
		case sf::Mouse::Right:
			handled = TwMouseButton(mouseAction, TW_MOUSE_RIGHT);
			break;
		default:
			break;
		}
		break;
	case sf::Event::MouseWheelMoved:
		s_WheelPos += event->MouseWheel.Delta;
		handled = TwMouseWheel(s_WheelPos);
		break;
	case sf::Event::Resized:
		// tell the new size to TweakBar
		TwWindowSize(event->Size.Width, event->Size.Height);
		// do not set 'handled', sf::Event::Resized may be also processed by the client application
		break;
	default:
		break;
	}

	return handled;
}

#endif // !defined TW_NO_SFML_EVENTS
